home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 11: TSX-11 / Linux Cubed Series 11 - TSX-11 Vol 1.iso / sbin / syslogd.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-11-30  |  20.5 KB  |  1,054 lines

  1. #ifndef lint
  2. static char sccsid[] = "@(#)syslogd.c";
  3. #endif not lint
  4.  
  5. /*
  6.  *  syslogd -- log system messages
  7.  *
  8.  * This program implements a system log. It takes a series of lines.
  9.  * Each line may have a priority, signified as "<n>" as
  10.  * the first characters of the line.  If this is
  11.  * not present, a default priority is used.
  12.  *
  13.  * To kill syslogd, send a signal 15 (terminate).  A signal 1 (hup) will
  14.  * cause it to reread its configuration file.
  15.  *
  16.  * Defined Constants:
  17.  *
  18.  * MAXLINE -- the maximimum line length that can be handled.
  19.  * NLOGS   -- the maximum number of simultaneous log files.
  20.  * DEFUPRI -- the default priority for user messages
  21.  * DEFSPRI -- the default priority for kernel messages
  22.  *
  23.  */
  24.  
  25. #define    NLOGS        20        /* max number of log files */
  26. #define    MAXLINE        1024        /* maximum line length */
  27. #define DEFUPRI        (LOG_USER|LOG_NOTICE)
  28. #define DEFSPRI        (LOG_KERN|LOG_CRIT)
  29. #define MARKCOUNT    10        /* ratio of minor to major marks */
  30.  
  31. #include <errno.h>
  32. #include <stdio.h>
  33. #include <sys/types.h>
  34. #include <utmp.h>
  35. #include <ctype.h>
  36. #include <signal.h>
  37. #include <sysexits.h>
  38. #include <string.h>
  39.  
  40. #include <sys/syslog.h>
  41. #include <sys/param.h>
  42. #include <sys/ioctl.h>
  43. #include <sys/stat.h>
  44. #include <sys/file.h>
  45. #include <sys/uio.h>
  46. #include <sys/time.h>
  47. #include <sys/socket.h>
  48.  
  49. typedef int (*sighand)();
  50.  
  51. char    *LogName = "/dev/log";
  52. char    *ConfFile = "/etc/syslog.conf";
  53. char    *PidFile = "/etc/syslog.pid";
  54. char    ctty[] = "/dev/tty0";
  55.  
  56. #define FDMASK(fd)    (1 << (fd))
  57.  
  58. /*
  59.  *    defines for BSD compat....I think!
  60.  */
  61.  
  62. #define index(a, b)    strchr(a, b)
  63. #define bzero(a, b)    memset(a, '\0', b)
  64.  
  65.  
  66. #define    dprintf        if (Debug) printf
  67.  
  68. #define UNAMESZ        8    /* length of a login name */
  69. #define MAXUNAMES    20    /* maximum number of user names */
  70. #define MAXFNAME    200    /* max file pathname length */
  71.  
  72. #define NOPRI        0x10    /* the "no priority" priority */
  73. #define    LOG_MARK    (LOG_NFACILITIES << 3)    /* mark "facility" */
  74.  
  75. /*
  76.  * Flags to logmsg().
  77.  */
  78.  
  79. #define IGN_CONS    0x001    /* don't print on console */
  80. #define SYNC_FILE    0x002    /* do fsync on file after printing */
  81. #define NOCOPY        0x004    /* don't suppress duplicate messages */
  82. #define ADDDATE        0x008    /* add a date to the message */
  83. #define MARK        0x010    /* this message is a mark */
  84.  
  85. /*
  86.  * This structure represents the files that will have log
  87.  * copies printed.
  88.  */
  89.  
  90. struct filed {
  91.     short    f_type;            /* entry type, see below */
  92.     short    f_file;            /* file descriptor */
  93.     time_t    f_time;            /* time this was last written */
  94.     u_char    f_pmask[LOG_NFACILITIES+1];    /* priority mask */
  95.     union {
  96.         char    f_uname[MAXUNAMES][UNAMESZ+1];
  97.         char    f_fname[MAXFNAME];
  98.     } f_un;
  99. };
  100.  
  101. /* values for f_type */
  102. #define F_UNUSED    0        /* unused entry */
  103. #define F_FILE        1        /* regular file */
  104. #define F_TTY        2        /* terminal */
  105. #define F_CONSOLE    3        /* console terminal */
  106. #define F_FORW        4        /* remote machine */
  107. #define F_USERS        5        /* list of users */
  108. #define F_WALL        6        /* everyone logged on */
  109.  
  110. /* how often (in seconds) to check for more input */
  111. #define GRANULARITY 10
  112. #define MSG_BSIZE 1024
  113.  
  114. char    *TypeNames[7] = {
  115.     "UNUSED",    "FILE",        "TTY",        "CONSOLE",
  116.     "FORW",        "USERS",    "WALL"
  117. };
  118.  
  119. struct filed    Files[NLOGS];
  120.  
  121. int    Debug;            /* debug flag */
  122. char    LocalHostName[MAXHOSTNAMELEN+1];    /* our hostname */
  123. char    *LocalDomain;        /* our local domain name */
  124. int    InetInuse = 0;        /* non-zero if INET sockets are being used */
  125. int    LogPort;        /* port number for INET connections */
  126. char    PrevLine[MAXLINE + 1];    /* copy of last line to supress repeats */
  127. char    PrevHost[MAXHOSTNAMELEN+1];        /* previous host */
  128. int    PrevFlags;
  129. int    PrevPri;
  130. int    PrevCount = 0;        /* number of times seen */
  131. int    Initialized = 0;    /* set when we have initialized ourselves */
  132. int    MarkInterval = 20;    /* interval between marks in minutes */
  133. int    MarkSeq = 0;        /* mark sequence number */
  134. int    Gran = 0;
  135. static int mask = 0;
  136. int count;
  137. int readfds;
  138.  
  139. extern    int errno, sys_nerr;
  140. extern    char *sys_errlist[];
  141. extern    char *ctime();
  142. /* extern  char *index(); */
  143.  
  144. main(argc, argv)
  145.     int argc;
  146.     char **argv;
  147. {
  148.     register int i;
  149.     register char *p;
  150.     static int funix;
  151.     int len, nlen, ns, nfds;
  152.     struct sockaddr afunix, fromunix;
  153.     int fd;
  154.     FILE *fp;
  155.     char *lp, *lpb;
  156.     char errbuf[100];
  157.     char line[MSG_BSIZE + 1];
  158.     extern int die(), domark();
  159.  
  160.     while (--argc > 0) {
  161.         p = *++argv;
  162.         if (p[0] != '-')
  163.             usage();
  164.         switch (p[1]) {
  165.         case 'f':        /* configuration file */
  166.             if (p[2] != '\0')
  167.                 ConfFile = &p[2];
  168.             break;
  169.  
  170.         case 'd':        /* debug */
  171.             Debug++;
  172.             break;
  173.  
  174.         case 'p':        /* path */
  175.             if (p[2] != '\0')
  176.                 LogName = &p[2];
  177.             break;
  178.  
  179.         case 'm':        /* mark interval */
  180.             if (p[2] != '\0')
  181.                 MarkInterval = atoi(&p[2]);
  182.             break;
  183.  
  184.         default:
  185.             usage();
  186.         }
  187.     }
  188.  
  189.     if (!Debug) {
  190.         if (fork())
  191.             exit(0);
  192.         for (i = 0; i < 10; i++)
  193.              close(i);
  194.         open("/", 0);
  195.         dup2(0, 1);
  196.         dup2(0, 2);
  197.         untty();
  198.     } else
  199. #ifdef linux
  200.     ;
  201. #else
  202.         setlinebuf(stdout);
  203. #endif
  204.     gethostname(LocalHostName, sizeof LocalHostName);
  205.     if (p = index(LocalHostName, '.')) {
  206.         *p++ = '\0';
  207.         LocalDomain = p;
  208.     }
  209.     else
  210.         LocalDomain = "";
  211.      signal(SIGTERM, (void *) die);
  212.      signal(SIGINT, Debug ? (void *) die : SIG_IGN);
  213.      signal(SIGQUIT, Debug ? (void *) die : SIG_IGN);
  214.      unlink(LogName);
  215. /*
  216.  *    create system logfile LogName mode 0666
  217.  *    logerror and die if can't
  218.  */
  219.  
  220.     funix = socket(AF_UNIX, SOCK_STREAM, 0);
  221.     if (funix < 0) {
  222.         logerror("unable to create socket");
  223.         die(0);
  224.     }
  225.     afunix.sa_family = AF_UNIX;
  226.     strcpy(afunix.sa_data, LogName);
  227.     if (bind(funix, &afunix, sizeof(afunix)) < 0) {
  228.         logerror("can't bind");
  229.         die(0);
  230.     }
  231.     chmod(LogName, 0666);
  232.  
  233.     /* tuck my process id away */
  234.     fp = fopen(PidFile, "w");
  235.     if (fp != NULL) {
  236.         fprintf(fp, "%d\n", getpid());
  237.          fclose(fp);
  238.     }
  239.  
  240.     dprintf("off & running....\n");
  241.  
  242.     init();
  243.     signal(SIGHUP, (void *) init);
  244.     signal(SIGALRM, (void *) domark);
  245.  
  246.     if (listen(funix, 5) < 0) {
  247.         perror("listen");
  248.         exit(1);
  249.     }
  250.  
  251.     alarm(MarkInterval * 60 / MARKCOUNT);
  252.  
  253.     for (;;) {
  254.         errno = 0;
  255. /*
  256.  *    Change this so it only reads one line at a time
  257.  *    otherwise if more than BUFSIZ messages are read
  258.  *    we'll get lost---also reading char at a time would
  259.  *    help us catch messages that are being written while
  260.  *    we run .... oh for an atomic flock
  261.  */
  262.  
  263.         readfds = FDMASK(funix) | mask;
  264.         errno = 0;
  265.         nfds = select(20, (fd_set *) &readfds, (fd_set *) NULL,
  266.             (fd_set *) NULL, (struct timeval *) NULL);
  267.         count++;
  268.         if (nfds == 0)
  269.             continue;
  270.         if (nfds < 0) {
  271.             if (errno != EINTR)
  272.                 perror("select");
  273.             continue;
  274.         }
  275.         if (readfds & (FDMASK(funix) | mask)) {
  276.             len = sizeof fromunix;
  277.             if ((i = recvfrom(funix, line, MSG_BSIZE, 0,
  278.                 (struct sockaddr *) &fromunix, &len)) > 0) {
  279.                 line[i]='\0';
  280.                 printline(LocalHostName, line);
  281.             } else {
  282.                 if ((errno == EAGAIN) || (errno == 0)) continue;
  283.                 sprintf(errbuf, "recvfrom unix %d: %s", errno, strerror(errno));
  284.                 logerror(errbuf);
  285.             }
  286.         } else {
  287.             if (errno != EINTR) {
  288.                 logerror("accept failure");
  289.                 die(0);
  290.             }
  291.         }
  292.     }
  293. }
  294.  
  295. usage()
  296. {
  297.     fprintf(stderr, "usage: syslogd [-d] [-mmarkinterval] [-ppath] [-fconffile]\n");
  298.     exit(1);
  299. }
  300.  
  301. untty()
  302. {
  303.     int i;
  304.  
  305.     if (!Debug) {
  306. #ifdef linux
  307.         setpgrp();
  308. #endif
  309.         i = open("/dev/tty", O_RDWR);
  310.         if (i >= 0) {
  311. #ifndef linux
  312.              ioctl(i, (int) TIOCNOTTY, (char *)0);
  313. #endif linux
  314.              close(i);
  315.         }
  316.     }
  317. }
  318.  
  319. /*
  320.  * Take a raw input line, decode the message, and print the message
  321.  * on the appropriate log files.
  322.  */
  323.  
  324. printline(hname, msg)
  325.     char *hname;
  326.     char *msg;
  327. {
  328.     register char *p, *q;
  329.     register int c;
  330.     char line[MAXLINE + 1];
  331.     int pri;
  332.  
  333.     /* test for special codes */
  334.     pri = DEFUPRI;
  335.     p = msg;
  336.     if (*p == '<') {
  337.         pri = 0;
  338.         while (isdigit(*++p))
  339.             pri = 10 * pri + (*p - '0');
  340.         if (*p == '>')
  341.             ++p;
  342.         if (pri <= 0 || pri >= (LOG_NFACILITIES << 3))
  343.             pri = DEFUPRI;
  344.     }
  345.  
  346.     /* don't allow users to log kernel messages */
  347.     if ((pri & LOG_PRIMASK) == LOG_KERN)
  348.         pri |= LOG_USER;
  349.  
  350.     q = line;
  351.  
  352.     while ((c = *p++ & 0177) != '\0' && c != '\n' &&
  353.         q < &line[sizeof(line) - 1]) {
  354.         if (iscntrl(c)) {
  355.             *q++ = '^';
  356.             *q++ = c ^ 0100;
  357.         } else
  358.             *q++ = c;
  359.     }
  360.     *q = '\0';
  361.  
  362.     logmsg(pri, line, hname, 0);
  363. }
  364.  
  365.  
  366. /*
  367.  * Log a message to the appropriate log files, users, etc. based on
  368.  * the priority.
  369.  */
  370.  
  371. logmsg(pri, msg, from, flags)
  372.     int pri;
  373.     char *msg, *from;
  374.     int flags;
  375. {
  376.     register struct filed *f;
  377.     register int l;
  378.     int fac, prilev;
  379.     time_t now;
  380.     int omask;
  381.     sighand s1, s2;
  382.     struct iovec iov[6];
  383.     register struct iovec *v = iov;
  384.     char line[MAXLINE + 1];
  385.  
  386.     dprintf("logmsg: pri %o, flags %x, from %s, msg %s\n", pri, flags, from, msg);
  387.  
  388.     s1 = signal(SIGHUP, SIG_IGN);
  389.     s2 = signal(SIGALRM, SIG_IGN);
  390.  
  391.     /*
  392.      * Check to see if msg looks non-standard.
  393.      */
  394.     if (strlen(msg) < 16 || msg[3] != ' ' || msg[6] != ' ' ||
  395.         msg[9] != ':' || msg[12] != ':' || msg[15] != ' ')
  396.         flags |= ADDDATE;
  397.  
  398.     if (!(flags & NOCOPY)) {
  399.         if (flags & (ADDDATE|MARK))
  400.             flushmsg();
  401.         else if (!strcmp(msg + 16, PrevLine + 16)) {
  402.             /* we found a match, update the time */
  403.              strncpy(PrevLine, msg, 15);
  404.             PrevCount++;
  405.             signal(SIGHUP, (void *) s1);
  406.             signal(SIGALRM, (void *) s2);
  407.             return;
  408.         } else {
  409.             /* new line, save it */
  410.             flushmsg();
  411.              strcpy(PrevLine, msg);
  412.              strcpy(PrevHost, from);
  413.             PrevFlags = flags;
  414.             PrevPri = pri;
  415.         }
  416.     }
  417.  
  418.      time(&now);
  419.     if (flags & ADDDATE)
  420.         v->iov_base = ctime(&now) + 4;
  421.     else
  422.         v->iov_base = msg;
  423.     v->iov_len = 15;
  424.     v++;
  425.     v->iov_base = " ";
  426.     v->iov_len = 1;
  427.     v++;
  428.     v->iov_base = from;
  429.     v->iov_len = strlen(v->iov_base);
  430.     v++;
  431.     v->iov_base = " ";
  432.     v->iov_len = 1;
  433.     v++;
  434.     if (flags & ADDDATE)
  435.         v->iov_base = msg;
  436.     else
  437.         v->iov_base = msg + 16;
  438.     v->iov_len = strlen(v->iov_base);
  439.     v++;
  440.  
  441.     /* extract facility and priority level */
  442.     fac = (pri & LOG_FACMASK) >> 3;
  443.     if (flags & MARK)
  444.         fac = LOG_NFACILITIES;
  445.     prilev = pri & LOG_PRIMASK;
  446.  
  447.     /* log the message to the particular outputs */
  448.     if (!Initialized) {
  449.         int cfd = open(ctty, O_WRONLY);
  450.  
  451.         if (cfd >= 0) {
  452.             v->iov_base = "\r\n";
  453.             v->iov_len = 2;
  454.              writev(cfd, iov, 6);
  455.              close(cfd);
  456.         }
  457.         untty();
  458.         signal(SIGHUP, (void *) s1);
  459.         signal(SIGALRM, (void *) s2);
  460.         return;
  461.     }
  462.     for (f = Files; f < &Files[NLOGS]; f++) {
  463.         /* skip messages that are incorrect priority */
  464.         if (f->f_pmask[fac] < prilev || f->f_pmask[fac] == NOPRI)
  465.             continue;
  466.  
  467.         /* don't output marks to recently written files */
  468.         if ((flags & MARK) && (now - f->f_time) < (MarkInterval * 60 / 2))
  469.             continue;
  470.  
  471.         dprintf("Logging to %s", TypeNames[f->f_type]);
  472.         f->f_time = now;
  473.         switch (f->f_type) {
  474.         case F_UNUSED:
  475.             dprintf("\n");
  476.             break;
  477.  
  478.         case F_FORW:
  479.             dprintf("Forward (unsupported)\n");
  480.             break;
  481.  
  482.         case F_CONSOLE:
  483.             if (flags & IGN_CONS) {
  484.                 dprintf(" (ignored)\n");
  485.                 break;
  486.             }
  487.  
  488.         case F_TTY:
  489.         case F_FILE:
  490.             dprintf(" %s\n", f->f_un.f_fname);
  491.             if (f->f_type != F_FILE) {
  492.                 v->iov_base = "\r\n";
  493.                 v->iov_len = 2;
  494.             } else {
  495.                 v->iov_base = "\n";
  496.                 v->iov_len = 1;
  497.             }
  498.             if (writev(f->f_file, iov, 6) < 0) {
  499.                 int e = errno;
  500.                  close(f->f_file);
  501.                 /*
  502.                  * Check for EBADF on TTY's due to vhangup() XXX
  503.                  */
  504.                 if (e == EBADF && f->f_type != F_FILE) {
  505.                     f->f_file = open(f->f_un.f_fname, O_WRONLY|O_APPEND);
  506.                     if (f->f_file < 0) {
  507.                         f->f_type = F_UNUSED;
  508.                         logerror(f->f_un.f_fname);
  509.                     }
  510.                 } else {
  511.                     f->f_type = F_UNUSED;
  512.                     errno = e;
  513.                     logerror(f->f_un.f_fname);
  514.                 }
  515.             } else if (flags & SYNC_FILE)
  516. #ifndef linux
  517.                  fsync(f->f_file);
  518. #else
  519.                  sync();
  520. #endif
  521.             break;
  522.  
  523.         case F_USERS:
  524.         case F_WALL:
  525.             dprintf("\n");
  526.             v->iov_base = "\r\n";
  527.             v->iov_len = 2;
  528.             wallmsg(f, iov);
  529.             break;
  530.         }
  531.     }
  532.     signal(SIGHUP, (void *) s1);
  533.     signal(SIGALRM, (void *) s2);
  534. }
  535.  
  536.  
  537. /*
  538.  *  WALLMSG -- Write a message to the world at large
  539.  *
  540.  *    Write the specified message to either the entire
  541.  *    world, or a list of approved users.
  542.  */
  543.  
  544. wallmsg(f, iov)
  545.     register struct filed *f;
  546.     struct iovec *iov;
  547. {
  548.     register char *p;
  549.     register int i;
  550.     int ttyf, len, pid, wstat, xpid;
  551.     FILE *uf;
  552.     static int reenter = 0;
  553.     struct utmp ut;
  554.     time_t now;
  555.     char greetings[200];
  556.  
  557.     if (reenter++)
  558.         return;
  559.  
  560.     /* open the user login file */
  561.     if ((uf = fopen("/etc/utmp", "r")) == NULL) {
  562.         logerror("/etc/utmp");
  563.         reenter = 0;
  564.         return;
  565.     }
  566.  
  567.      time(&now);
  568.      sprintf(greetings,
  569.         "\r\n\7Message from syslogd@%s at %.24s ...\r\n",
  570.         iov[2].iov_base, ctime(&now));
  571.     len = strlen(greetings);
  572.  
  573.     /* scan the user login file */
  574.     xpid = 0;
  575.     while (fread((char *) &ut, sizeof ut, 1, uf) == 1) {
  576.         /* is this slot used? */
  577.         if (ut.ut_name[0] == '\0')
  578.             continue;
  579.  
  580.         /* should we send the message to this user? */
  581.         if (f->f_type == F_USERS) {
  582.             for (i = 0; i < MAXUNAMES; i++) {
  583.                 if (!f->f_un.f_uname[i][0]) {
  584.                     i = MAXUNAMES;
  585.                     break;
  586.                 }
  587.                 if (strncmp(f->f_un.f_uname[i], ut.ut_name,
  588.                     UNAMESZ) == 0)
  589.                     break;
  590.             }
  591.             if (i >= MAXUNAMES)
  592.                 continue;
  593.         }
  594.  
  595.         /* compute the device name */
  596.         p = "/dev/12345678";
  597.         strncpy(&p[5], ut.ut_line, UNAMESZ);
  598.  
  599.         /*
  600.          * Might as well   instead of using nonblocking I/O
  601.          * and doing notty().
  602.          */
  603.         pid = fork();
  604. /*        if (pid != 0) {
  605.             while ((xpid = wait(&wstat)) != pid) {
  606.                 if (xpid == -1)
  607.                     break;
  608.             }
  609.         } else
  610. */        if (pid == 0) {
  611.             if (f->f_type == F_WALL) {
  612.                 iov[0].iov_base = greetings;
  613.                 iov[0].iov_len = len;
  614.                 iov[1].iov_len = 0;
  615.             }
  616.              signal(SIGALRM, SIG_DFL);
  617.              alarm(30);
  618.             /* open the terminal */
  619.             ttyf = open(p, O_WRONLY);
  620.             if (ttyf >= 0)
  621.                  writev(ttyf, iov, 6);
  622.             exit(0);
  623.         }
  624.     }
  625.     /* close the user login file */
  626.      fclose(uf);
  627.     while ((xpid = wait(&wstat)) != -1) ;
  628.     reenter = 0;
  629. }
  630.  
  631.  
  632. domark()
  633. {
  634.     int pri;
  635.  
  636.     if ((++MarkSeq % MARKCOUNT) == 0)
  637.         logmsg(LOG_INFO, "-- MARK --", LocalHostName, ADDDATE|MARK);
  638.     else
  639.         flushmsg();
  640.     signal(SIGALRM, (void *) domark);
  641.     alarm(MarkInterval * 60 / MARKCOUNT);
  642. }
  643.  
  644. flushmsg()
  645. {
  646.     if (PrevCount == 0)
  647.         return;
  648.     if (PrevCount > 1)
  649.          sprintf(PrevLine+16, "last message repeated %d times", PrevCount);
  650.     PrevCount = 0;
  651.     logmsg(PrevPri, PrevLine, PrevHost, PrevFlags|NOCOPY);
  652.     PrevLine[0] = '\0';
  653. }
  654.  
  655. /*
  656.  * Print syslogd errors some place.
  657.  */
  658. logerror(type)
  659.     char *type;
  660. {
  661.     char buf[100];
  662.  
  663.     if (errno == 0)
  664.          sprintf(buf, "syslogd: %s", type);
  665.     else if ((unsigned) errno > sys_nerr)
  666.          sprintf(buf, "syslogd: %s: error %d", type, errno);
  667.     else
  668.          sprintf(buf, "syslogd: %s: %s", type, sys_errlist[errno]);
  669.     errno = 0;
  670.     dprintf("%s\n", buf);
  671.     logmsg(LOG_SYSLOG|LOG_ERR, buf, LocalHostName, ADDDATE);
  672. }
  673.  
  674. die(sig)
  675. {
  676.     char buf[100];
  677.  
  678.     if (sig) {
  679.         dprintf("syslogd: going down on signal %d\n", sig);
  680.         flushmsg();
  681.          sprintf(buf, "going down on signal %d", sig);
  682.         logerror(buf);
  683.     }
  684.      unlink(LogName);
  685.     exit(0);
  686. }
  687.  
  688. /*
  689.  *  INIT -- Initialize syslogd from configuration table
  690.  */
  691.  
  692. init()
  693. {
  694.     register int i;
  695.     register FILE *cf;
  696.     register struct filed *f;
  697.     register char *p;
  698.     char cline[BUFSIZ];
  699.  
  700.     dprintf("init\n");
  701.  
  702.     /* flush any pending output */
  703.     flushmsg();
  704.  
  705.     /*
  706.      *  Close all open log files.
  707.      */
  708.     for (f = Files; f < &Files[NLOGS]; f++) {
  709.         if (f->f_type == F_FILE || f->f_type == F_TTY)
  710.              close(f->f_file);
  711.         f->f_type = F_UNUSED;
  712.     }
  713.  
  714.     /* open the configuration file */
  715.     if ((cf = fopen(ConfFile, "r")) == NULL) {
  716.         dprintf("cannot open %s\n", ConfFile);
  717.         cfline("*.ERR\t/dev/tty0", &Files[0]);
  718.         cfline("*.PANIC\t*", &Files[1]);
  719.         return;
  720.     }
  721.  
  722.     /*
  723.      *  Foreach line in the conf table, open that file.
  724.      */
  725.     f = Files;
  726.     while (fgets(cline, sizeof cline, cf) != NULL && f < &Files[NLOGS]) {
  727.         /* check for end-of-section */
  728.         if (cline[0] == '\n' || cline[0] == '#')
  729.             continue;
  730.  
  731.         /* strip off newline character */
  732.         p = index(cline, '\n');
  733.         if (p)
  734.             *p = '\0';
  735.  
  736.         cfline(cline, f++);
  737.     }
  738.  
  739.     /* close the configuration file */
  740.      fclose(cf);
  741.  
  742.     Initialized = 1;
  743.  
  744.     if (Debug) {
  745.         for (f = Files; f < &Files[NLOGS]; f++) {
  746.             for (i = 0; i <= LOG_NFACILITIES; i++)
  747.                 if (f->f_pmask[i] == NOPRI)
  748.                     printf("X ");
  749.                 else
  750.                     printf("%d ", f->f_pmask[i]);
  751.             printf("%s: ", TypeNames[f->f_type]);
  752.             switch (f->f_type) {
  753.             case F_FILE:
  754.             case F_TTY:
  755.             case F_CONSOLE:
  756.                 printf("%s", f->f_un.f_fname);
  757.                 break;
  758.  
  759.             case F_FORW:
  760.                 break;
  761.  
  762.             case F_USERS:
  763.                 for (i = 0; i < MAXUNAMES && *f->f_un.f_uname[i]; i++)
  764.                     printf("%s, ", f->f_un.f_uname[i]);
  765.                 break;
  766.             }
  767.             printf("\n");
  768.         }
  769.     }
  770.  
  771.     logmsg(LOG_SYSLOG|LOG_INFO, "syslogd: restart", LocalHostName, ADDDATE);
  772.     dprintf("syslogd: restarted\n");
  773. }
  774.  
  775. /*
  776.  * Crack a configuration file line
  777.  */
  778.  
  779. struct code {
  780.     char    *c_name;
  781.     int    c_val;
  782. };
  783.  
  784. struct code    PriNames[] = {
  785.     "panic",    LOG_EMERG,
  786.     "emerg",    LOG_EMERG,
  787.     "alert",    LOG_ALERT,
  788.     "crit",        LOG_CRIT,
  789.     "err",        LOG_ERR,
  790.     "error",    LOG_ERR,
  791.     "warn",        LOG_WARNING,
  792.     "warning",    LOG_WARNING,
  793.     "notice",    LOG_NOTICE,
  794.     "info",        LOG_INFO,
  795.     "debug",    LOG_DEBUG,
  796.     "none",        NOPRI,
  797.     NULL,        -1
  798. };
  799.  
  800. struct code    FacNames[] = {
  801.     "kern",        LOG_KERN,
  802.     "user",        LOG_USER,
  803.     "mail",        LOG_MAIL,
  804.     "daemon",    LOG_DAEMON,
  805.     "auth",        LOG_AUTH,
  806.     "security",    LOG_AUTH,
  807.     "mark",        LOG_MARK,
  808.     "syslog",    LOG_SYSLOG,
  809.     "lpr",        LOG_LPR,
  810.     "local0",    LOG_LOCAL0,
  811.     "local1",    LOG_LOCAL1,
  812.     "local2",    LOG_LOCAL2,
  813.     "local3",    LOG_LOCAL3,
  814.     "local4",    LOG_LOCAL4,
  815.     "local5",    LOG_LOCAL5,
  816.     "local6",    LOG_LOCAL6,
  817.     "local7",    LOG_LOCAL7,
  818.     NULL,        -1
  819. };
  820.  
  821. cfline(line, f)
  822.     char *line;
  823.     register struct filed *f;
  824. {
  825.     register char *p;
  826.     register char *q;
  827.     register int i;
  828.     char *bp;
  829.     int pri;
  830.     struct hostent *hp;
  831.     char buf[MAXLINE];
  832.  
  833.     dprintf("cfline(%s)\n", line);
  834.  
  835.     /* clear out file entry */
  836.     bzero((char *) f, sizeof *f);
  837.     for (i = 0; i <= LOG_NFACILITIES; i++)
  838.         f->f_pmask[i] = NOPRI;
  839.  
  840.     /* scan through the list of selectors */
  841.     for (p = line; *p && *p != '\t';) {
  842.  
  843.         /* find the end of this facility name list */
  844.         for (q = p; *q && *q != '\t' && *q++ != '.'; )
  845.             continue;
  846.  
  847.         /* collect priority name */
  848.         for (bp = buf; *q && !index("\t,;", *q); )
  849.             *bp++ = *q++;
  850.         *bp = '\0';
  851.  
  852.         /* skip cruft */
  853.         while (index(", ;", *q))
  854.             q++;
  855.  
  856.         /* decode priority name */
  857.         pri = decode(buf, PriNames);
  858.         if (pri < 0) {
  859.             char xbuf[200];
  860.  
  861.              sprintf(xbuf, "unknown priority name \"%s\"", buf);
  862.             logerror(xbuf);
  863.             return;
  864.         }
  865.  
  866.         /* scan facilities */
  867.         while (*p && !index("\t.;", *p)) {
  868.             int i;
  869.  
  870.             for (bp = buf; *p && !index("\t,;.", *p); )
  871.                 *bp++ = *p++;
  872.             *bp = '\0';
  873.             if (*buf == '*')
  874.                 for (i = 0; i < LOG_NFACILITIES; i++)
  875.                     f->f_pmask[i] = pri;
  876.             else {
  877.                 i = decode(buf, FacNames);
  878.                 if (i < 0) {
  879.                     char xbuf[200];
  880.  
  881.                      sprintf(xbuf, "unknown facility name \"%s\"", buf);
  882.                     logerror(xbuf);
  883.                     return;
  884.                 }
  885.                 f->f_pmask[i >> 3] = pri;
  886.             }
  887.             while (*p == ',' || *p == ' ')
  888.                 p++;
  889.         }
  890.  
  891.         p = q;
  892.     }
  893.  
  894.     /* skip to action part */
  895.     while (*p == '\t')
  896.         p++;
  897.  
  898. fprintf(stderr, "syslogd: cfline on %s\n", p);
  899.  
  900.     switch (*p)
  901.     {
  902.     case '@':
  903.         if (!InetInuse)
  904.             break;
  905.          strcpy(f->f_un.f_uname, ++p);
  906.  
  907.         f->f_type = F_FORW;
  908.         break;
  909.  
  910.     case '/':
  911.          strcpy(f->f_un.f_fname, p);
  912.         if ((f->f_file = open(p, O_WRONLY|O_APPEND)) < 0) {
  913.             logerror(p);
  914.             break;
  915.         }
  916.  
  917.         if (isatty(f->f_file)) {
  918.             f->f_type = F_TTY;
  919.             untty();
  920.         }
  921.         else
  922.             f->f_type = F_FILE;
  923.         if (strcmp(p, ctty) == 0)
  924.             f->f_type = F_CONSOLE;
  925.         break;
  926.  
  927.     case '*':
  928.         f->f_type = F_WALL;
  929.         break;
  930.  
  931.     default:
  932.         for (i = 0; i < MAXUNAMES && *p; i++) {
  933.             for (q = p; *q && *q != ','; )
  934.                 q++;
  935.              strncpy(f->f_un.f_uname[i], p, UNAMESZ);
  936.             if ((q - p) > UNAMESZ)
  937.                 f->f_un.f_uname[i][UNAMESZ] = '\0';
  938.             else
  939.                 f->f_un.f_uname[i][q - p] = '\0';
  940.             while (*q == ',' || *q == ' ')
  941.                 q++;
  942.             p = q;
  943.         }
  944.         f->f_type = F_USERS;
  945.         break;
  946.     }
  947. }
  948.  
  949.  
  950. /*
  951.  *  Decode a symbolic name to a numeric value
  952.  */
  953.  
  954. decode(name, codetab)
  955.     char *name;
  956.     struct code *codetab;
  957. {
  958.     register struct code *c;
  959.     register char *p;
  960.     char buf[40];
  961.  
  962.     if (isdigit(*name))
  963.         return (atoi(name));
  964.  
  965.      strcpy(buf, name);
  966.     for (p = buf; *p; p++)
  967.         if (isupper(*p))
  968.             *p = tolower(*p);
  969.     for (c = codetab; c->c_name; c++)
  970.         if (!strcmp(buf, c->c_name))
  971.             return (c->c_val);
  972.  
  973.     return (-1);
  974. }
  975.  
  976. readline(fd, s, size)
  977. int fd;
  978. char *s;
  979. int size;
  980. {
  981.     int c, i, j;
  982.     static long cur_pos;
  983.     struct stat st;
  984.  
  985.     fstat(fd, &st);
  986.     if (cur_pos < st.st_size) {
  987.         i = 0; j = 0;
  988.         do {
  989.             j = read(fd, &c, 1);
  990.             *s++ = c;
  991.             i++;
  992.         } while (j > 0 && c != '\n');
  993.         cur_pos = lseek(fd, 0L, 1);
  994.         return(i);
  995.     }
  996.     return(0);
  997. }
  998.  
  999. int
  1000. recvfrom(s, buf, buflen, flags, sock, socklen)
  1001. int s, buflen, flags;
  1002. char *buf;
  1003. struct sockaddr *sock;
  1004. int *socklen;
  1005. {
  1006.     int i, fd, nfds, cc;
  1007.     long newmask;
  1008.  
  1009.     /* check for dead connections */
  1010.  
  1011.     /* I think this is done below now */
  1012.  
  1013.     /* check for data on current connections and return */
  1014.  
  1015.     if (mask | FDMASK(s)) {
  1016.         newmask = mask | FDMASK(s);
  1017.         nfds = select(20, (fd_set *) &newmask, (fd_set *) NULL,
  1018.             (fd_set *) NULL, (struct timeval *) NULL);
  1019.     
  1020.         fd = 0;
  1021.         while (nfds > 0) {
  1022.     /* accept new connection and read data */
  1023.  
  1024.             if (newmask & FDMASK(s)) {
  1025.                 listen(s, 5);
  1026.                 fd = accept(s, sock, socklen);
  1027.                 if (fd < 0) {
  1028.                     return -1;
  1029.                 }
  1030.                 mask |= FDMASK(fd);
  1031.                 fcntl(fd, F_SETFL, O_NONBLOCK);
  1032.                 cc = read(fd, buf, buflen);
  1033.                 return(cc);
  1034.             } else {
  1035.                 while (!(newmask & 1)) {
  1036.                     newmask = newmask >> 1;
  1037.                     fd++;
  1038.                 }
  1039.                 cc = read(fd, buf, buflen);
  1040.                 if (cc <= 0) {
  1041.                     mask ^= FDMASK(fd);
  1042.                     newmask = newmask >> 1;
  1043.                     close(fd);
  1044.                     fd++;
  1045.                     nfds--;
  1046.                 } else {
  1047.                     return(cc);
  1048.                 }
  1049.             }
  1050.         }
  1051.     }
  1052. }
  1053.  
  1054.